const { join } = require('path');
const fs = require('fs');
const {
  PUBLIC_KEY,
  PRIVATE_KEY,
  JSONQL_PATH,
  CONTENT_TYPE,
  DEFAULT_RESOLVER_DIR,
  DEFAULT_CONTRACT_DIR,
  CONTRACT_KEY_NAME,
  ARRAY_TYPE,
  BOOLEAN_TYPE,
  STRING_TYPE,
  NUMBER_TYPE,
  OBJECT_TYPE,
  ARGS_KEY,
  TYPE_KEY,
  ENUM_KEY,
  CHECKER_KEY,
  ACCEPTED_JS_TYPES,
  CJS_TYPE,
  ISSUER_NAME,
  LOGOUT_NAME,
  VALIDATOR_NAME,
  RETURN_AS_JSON,
  DEFAULT_KEYS_DIR,
  DEFAULT_PUBLIC_KEY_FILE,
  DEFAULT_PRIVATE_KEY_FILE,
  RSA_MIN_MODULE_LEN
} = require('jsonql-constants')
const {
  createConfig,
  constructConfig
} = require('jsonql-params-validator')
// const NodeCache = require('node-cache');
// const mcache = new NodeCache;
// @BUG when we deploy it in docker, or using systemd the workingDirectory affect the
// execute path, it might be better to allow a config option of workingDirectory and
// use that as base
const dirname = process.cwd()
// @TODO we need to create the same fn to clear out the options like I did in server-io-core
const constProps = {
  __checked__: true,
  contentType: CONTENT_TYPE,
  contract: false,
  initContract: false,
  useDoc: true,
  returnAs: RETURN_AS_JSON,
  privateKey: false,
  publicKey: false,
  initJwtKeys: false
}

const appProps = {
  name: createConfig('jsonql-koa', [STRING_TYPE]), // this is for ID which one is which when use as ms
  expired: createConfig(0, [NUMBER_TYPE]),
  // allow user to change their auth type methods name
  loginHandlerName: createConfig(ISSUER_NAME, [STRING_TYPE]),
  logoutHandlerName: createConfig(LOGOUT_NAME, [STRING_TYPE]),
  validatorHandlerName: createConfig(VALIDATOR_NAME, [STRING_TYPE, BOOLEAN_TYPE]),
  // this flag will change many things
  enableAuth: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE},
  // from now on always turn this to on
  useJwt: createConfig(true, [BOOLEAN_TYPE, STRING_TYPE]),
  jwtTokenOption: createConfig(false, [BOOLEAN_TYPE, OBJECT_TYPE]),
  // add in v1.3.0
  enableJsonp: createConfig(false, [BOOLEAN_TYPE]),
  // show or hide the description field in the public contract
  contractWithDesc: createConfig(false, [BOOLEAN_TYPE]),
  // @1.3.4 whenever generate a contract will generate the public contract as well
  withPublicContract: createConfig(true, [BOOLEAN_TYPE]),
  keysDir: createConfig(join(dirname, DEFAULT_KEYS_DIR), [STRING_TYPE]),
  publicKeyFileName: createConfig(DEFAULT_PUBLIC_KEY_FILE, [STRING_TYPE]),
  privateKeyFileName: createConfig(DEFAULT_PRIVATE_KEY_FILE, [STRING_TYPE]),
  rsaModulusLength: createConfig(RSA_MIN_MODULE_LEN, [NUMBER_TYPE]),

  jsonqlPath: {[ARGS_KEY]: ['/', JSONQL_PATH].join(''), [TYPE_KEY]: STRING_TYPE},
  resolverDir: {[ARGS_KEY]: join(dirname, DEFAULT_RESOLVER_DIR), [TYPE_KEY]: STRING_TYPE, [CHECKER_KEY]: fs.existsSync},
  // we don't really need to check if the contract directory exist or not, it will get created
  contractDir: {[ARGS_KEY]: join(dirname, DEFAULT_CONTRACT_DIR), [TYPE_KEY]: STRING_TYPE},

  contractKey: {[ARGS_KEY]: false, [TYPE_KEY]: [BOOLEAN_TYPE, STRING_TYPE]},
  contractKeyName: {[ARGS_KEY]: CONTRACT_KEY_NAME, [TYPE_KEY]: STRING_TYPE},

  publicMethodDir: createConfig(PUBLIC_KEY, [STRING_TYPE]),
  // just try this with string type first
  privateMethodDir: constructConfig(PRIVATE_KEY, [STRING_TYPE], true),

  // new feature for v.1.1 release
  // if the developer pass the nodeClient config then we will pre-generate the calling method
  // for them. We expect them to named the client so it will be key:value pair

  enableWebConsole: {[ARGS_KEY]: false, [TYPE_KEY]: [BOOLEAN_TYPE, OBJECT_TYPE]}, // you need to actively enable this option to have the web console enable
  jsType: {[ARGS_KEY]: CJS_TYPE, [TYPE_KEY]: STRING_TYPE, [ENUM_KEY]: ACCEPTED_JS_TYPES},

  // undecided properties
  // clientConfig: {[ARGS_KEY]: [], [TYPE_KEY]: ARRAY_TYPE}, // need to develop a new tool to validate and inject this
  exposeError: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // this will allow you to control if you want to throw your error back to your client

  // Perhaps I should build the same create options style like server-io-core
  autoCreateContract: {[ARGS_KEY]:  true, [TYPE_KEY]: BOOLEAN_TYPE},
  buildContractOnStart: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // process.env.NODE_ENV === 'development',
  keepLastContract: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // true keep last one, integer > 0 keep that number of files
  validateReturns: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // reserved for use in the future
  // For v1.5.0 to integrate the node-client
  clientConfig: createConfig([], [ARRAY_TYPE])
};

module.exports = {
  constProps,
  appProps,
  jwtProcessKey: 'INIT_JWT_KEYS' // just for id the promise call
};
